#ifndef _GSOLVERBBPV3_H_
#define _GSOLVERBBPV3_H_

#include <iostream>

using namespace std ;

#include "gsearchnode.h"
#include "gchrono.h"

#include "gsupplyLinkProblem.h"
#include "gsupplyLinkSolution.h"
#include "glowerbound.h"

// uncomment to DEBUG
//#define USE_DEBUG

// uncomment the following line to use MPI
#define USE_MPI


#define MAX_NODES  400
#define MAX_SLAVES MAX_NODES

// Msg From Slave to Master
#define BESTEVAL_FROM_SLAVE_TAG  110
#define ENDWORK_TAG              120


// Msg From Master to Slave
#define BESTEVAL_FROM_MASTER_TAG 210
#define WORK1_TAG                220
#define WORK2_TAG                221
#define WORK3_TAG                222
#define DIE_TAG                  240





/**
 * A BBP solver : starts with jobs with last due dates
 *
 * Dans cette version 3 de la BBP, on demarre avec les jobs reordonnes dans le sens des dates dues croissantes. Mais
 * contrairement a l'exploration brutale de la version 2, cette fois on ne considere pas n'importe quel numero de batch.
 * Pour chaque job, on choisit de le rajouter soit dans un batch deja existant dont la capacite residuel est suffisante
 * pour stocker le nouveau job, soit dans un nouveau batch.
 *
 * Le nouveau batch est ordonnance avant les autres batchs deja crees.
 *
 * ATTENTION : Pour que cette solution soit optimale, sachant que l'on
 * part d'un probleme pour lequel les jobs sont classes par date due croissante, il est egalement necessaire que le cout de stockage
 * de tous les jobs soient identiques. Dans le cas contraire, la solution ainsi construite n'est plus certaine d'etre optimale.
 */
class GSolverBBPv3 {
 protected:
  GSupplyLinkProblem& problem ;
  GSupplyLinkSolution bestSolution ;
  GSupplyLinkSolution bestSolutionDueDateOrdered ;
  GSupplyLinkSolution currentSolutionDueDateOrdered ;

  double maxValue ;

  /**
   * Minimum and Maximum number of batches
   */
  int minBatch, maxBatch;

  /**
   * OpenMPI
   */
  int node, nbrNodes ;

  /**
   *  For statistic usage
   */
  gchrono cpuTotal, cpuComputing, cpuMPIComm ;
  double cpuComputingUsage, cpuMPICommUsage ;

#ifdef USE_MPI
  MPI_Status status ;

  // Besteval for communication between nodes
  int buffer[2];
  double bestEvalMPI ;
#endif

 public:
  GSolverBBPv3(GSupplyLinkProblem& pb, int node_, int p_=0) ;
  virtual ~GSolverBBPv3() {}

  // Inlines
  inline GSupplyLinkSolution& getBestSolution() { return bestSolution ; }
  inline GSupplyLinkSolution& getBestSolutionDueDateOrdered() { return bestSolutionDueDateOrdered ; }
  inline void coutline() { cout << "------------------------------------------------" << endl ; }

  void solve() ;

  virtual void solveInit()=0 ;
  virtual void solveMain()=0 ;
  virtual void solveEnd() ;

  void initBestSolutionWithFFD() ;
} ;

#endif
